#[macro_use]
extern crate lazy_static;
pub mod command;
pub mod config;
pub mod controller;
pub mod error;
pub mod lock;
pub mod logging;
pub mod manager;
pub mod response;
pub mod serve;
pub mod util;
use std::sync::{Arc};
use clap::Parser;
use colored::Colorize;
use config::{ApplicationConfig, Opt};
pub use error::Error;
use manager::ManagerLock;
use state::TypeMap;
use tauri::{AppHandle, Manager, Runtime};
use tokio::sync::RwLock;
use tokio_cron_scheduler::JobScheduler;
pub use tracing::{debug, error, info, warn};
pub type Result<T> = std::result::Result<T, Error>;

pub static APPLICATION_CONTEXT: TypeMap![Send + Sync] = <TypeMap![Send + Sync]>::new();
pub type TypeJobScheduler = Arc<RwLock<JobScheduler>>;

use std::sync::atomic::{AtomicU64, Ordering, AtomicBool};
use std::time::{Duration, Instant};
use std::io::Write;
use std::sync::Mutex;

lazy_static! {
    static ref START_TIME: Mutex<Instant> = Mutex::new(Instant::now());
}

static LAST_ACTIVITY_TIME: AtomicU64 = AtomicU64::new(0);
const RESPONSE_TIMEOUT: Duration = Duration::from_secs(30);

pub async fn init_context() {
    display_banner();
    //从启动参数中获取开关 是否打印日志
    let opt = Opt::parse();
    let print_log = opt.print_log;
    init_logging("info", if print_log { Some("./logs/securitymanager.log")} else { None   }).unwrap();
    init_config().await;
    let sched =Arc::new(RwLock::new( JobScheduler::new().await.unwrap()));
    APPLICATION_CONTEXT.set(sched);
}

fn display_banner() {
    let banner = r#"
         ____                      _ _             
        / ___|  ___  ___ _ __ ___ (_) |_ ___  _ __ 
        \___ \ / _ \/ __| '_ ` _ \| | __/ _ \| '__|
        ___) |  __/ (__| | | | | | | || (_) | |   
        |____/ \___|\___|_| |_| |_|_|\__\___/|_|  
    "#;

    println!("{}", banner.bright_blue());
}

pub fn init_main_thread_monitor<R: Runtime>(app_handler: AppHandle<R>) {
    let app = app_handler.clone();
    
    // 重置启动时间和活动时间
    {
        let mut start_time = START_TIME.lock().unwrap();
        *start_time = Instant::now();
    }
    LAST_ACTIVITY_TIME.store(0, Ordering::SeqCst);
    update_main_thread_status();
    
    std::thread::spawn(move || {
        loop {
            std::thread::sleep(Duration::from_secs(10));
            
            let current_time = START_TIME.lock().unwrap().elapsed().as_secs();
            let last_activity = LAST_ACTIVITY_TIME.load(Ordering::SeqCst);
            
            info!("Last activity: {} seconds ago", current_time - last_activity);
            
            // 如果超过30秒没有活动，认为程序未响应
            if current_time - last_activity > RESPONSE_TIMEOUT.as_secs() {
                let error_msg = format!(
                    "=== Main thread not responding ===\nTime: {}\nLast activity: {} seconds ago\n",
                    chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
                    current_time - last_activity
                );
                
                if let Ok(mut file) = std::fs::OpenOptions::new()
                    .create(true)
                    .append(true)
                    .open("logs/crash.log") 
                {
                    let _ = file.write_all(error_msg.as_bytes());
                }
                
                eprintln!("{}", error_msg);
                app.restart();
                break;
            }
        }
    });
}

pub fn update_main_thread_status() {
    let current_time = START_TIME.lock().unwrap().elapsed().as_secs();
    LAST_ACTIVITY_TIME.store(current_time, Ordering::SeqCst);
}

pub fn init_panic_handler<R:Runtime>(app_handler:AppHandle<R>) {
    use std::panic;
    use std::process;
    use std::fs::OpenOptions;
    use std::io::Write;
    use chrono::Local;

    // 初始化主线程监控
    init_main_thread_monitor(app_handler.clone());

    panic::set_hook(Box::new(move |panic_info| {
        let location = panic_info.location().unwrap();
        let msg = panic_info.payload().downcast_ref::<&str>().unwrap_or(&"Unknown error");
        
        // 获取当前时间
        let now = Local::now();
        let timestamp = now.format("%Y-%m-%d %H:%M:%S").to_string();
        
        // 构建错误信息
        let error_msg = format!(
            "=== Panic occurred at {} ===\nTime: {}\nLocation: {}:{}\nError: {}\nBacktrace:\n{:?}\n",
            timestamp,
            timestamp,
            location.file(),
            location.line(),
            msg,
            backtrace::Backtrace::new()
        );

        // 写入错误日志文件
        if let Ok(mut file) = OpenOptions::new()
            .create(true)
            .append(true)
            .open("logs/crash.log") 
        {
            let _ = file.write_all(error_msg.as_bytes());
        }

        // 打印到控制台
        eprintln!("{}", error_msg);
        
        // 等待一小段时间确保日志写入
        std::thread::sleep(std::time::Duration::from_secs(1));
        
        // 退出当前进程
        app_handler.restart()
    }));
}

pub fn cryptmd5(data: &str) -> String {
    let hasher = md5::compute(data.as_bytes());
    format!("{:x}", hasher)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_single_instance::init(|_app, args, _cwd| {
            // 如果已经运行，则处理启动参数
            info!("启动参数: {:?}", args);
        }))
        .plugin(tauri_plugin_notification::init())
        .plugin(tauri_plugin_opener::init())
        .plugin(manager::init())
        .setup(|app| {
            //init_panic_handler(app.app_handle().clone());
            #[cfg(debug_assertions)] //仅在调试时自动打开开发者工具
            {
                let main_window = app.get_webview_window("main").unwrap();
                main_window.open_devtools();
                info!("打开开发者工具");
            }
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

pub trait Ext<R: Runtime> {
    fn manager(&self) -> Arc<ManagerLock>;
}

impl<R: Runtime, T: Manager<R>> crate::Ext<R> for T {
    fn manager(&self) -> Arc<ManagerLock> {
        let manager_lock = self.state::<Arc<ManagerLock>>().inner();
        manager_lock.clone()
    }
}

pub async fn init_config() {
    APPLICATION_CONTEXT.set(set_config().await);
}

async fn set_config() -> ApplicationConfig {
    /* let opt = Opt::parse();
    let content = match opt.config_path.as_str() {
        "" => {
            let path = "./config.toml";
            read_to_string(path).await.unwrap()
        }
        _ => read_to_string(opt.config_path.clone()).await.unwrap(),
    };
    info!("初始化配置: {}", &content); */
    ApplicationConfig {
        base_url: "https://manage.yunsuanfang.com".to_string(),
    }
}

pub fn init_logging(level: &str, file_path: Option<&str>) -> anyhow::Result<()> {
    use std::path::PathBuf;

    let level = match level.to_lowercase().as_str() {
        "trace" => tracing::Level::TRACE,
        "debug" => tracing::Level::DEBUG,
        "info" => tracing::Level::INFO,
        "warn" => tracing::Level::WARN,
        "error" => tracing::Level::ERROR,
        _ => tracing::Level::INFO,
    };

    let file_path = file_path.map(PathBuf::from);
    logging::init_logging(Some(level), file_path)
}
